#include "WizStringHash.hpp"

namespace Wiz
{
    namespace StringHash
    {
        namespace BKDR
        {
            /// Case sensitive
            ::Wiz::Index32::Type Calc(::Wiz::Char::ConstPtr InStr)
            {
                /// 31 131 1313 13131 131313 etc..
                static ::Wiz::UInt32::TypeConst Seed = 131;

                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = *InStr++)
                {
                    Hash = Hash * Seed + CurrChar;
                }

                return (Hash & ::Wiz::Index32::Max);
            }
            ::Wiz::Index32::Type Calc(::Wiz::WChar::ConstPtr InStr)
            {
                /// 31 131 1313 13131 131313 etc..
                static ::Wiz::UInt32::TypeConst Seed = 131;

                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = *InStr++)
                {
                    Hash = Hash * Seed + CurrChar;
                }

                return (Hash & ::Wiz::Index32::Max);
            }

            /// Case insensitive
            ::Wiz::Index32::Type CalcInCase(::Wiz::Char::ConstPtr InStr)
            {
                /// 31 131 1313 13131 131313 etc..
                static ::Wiz::UInt32::TypeConst Seed = 131;

                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = ::Wiz::ToUpper(*InStr++))
                {
                    Hash = Hash * Seed + CurrChar;
                }

                return (Hash & ::Wiz::Index32::Max);
            }
            ::Wiz::Index32::Type CalcInCase(::Wiz::WChar::ConstPtr InStr)
            {
                /// 31 131 1313 13131 131313 etc..
                static ::Wiz::UInt32::TypeConst Seed = 131;

                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = ::Wiz::ToUpper(*InStr++))
                {
                    Hash = Hash * Seed + CurrChar;
                }

                return (Hash & ::Wiz::Index32::Max);
            }
        } /// end of namespace BKDR

        namespace SDBM
        {
            /// Case sensitive
            ::Wiz::Index32::Type Calc(::Wiz::Char::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = *InStr++)
                {
                    /// equivalent to: hash = 65599*hash + (*str++);
                    Hash = (Hash << 6) + (Hash << 16) - Hash + CurrChar;
                }

                return (Hash & ::Wiz::Index32::Max);
            }
            ::Wiz::Index32::Type Calc(::Wiz::WChar::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = *InStr++)
                {
                    /// equivalent to: hash = 65599*hash + (*str++);
                    Hash = (Hash << 6) + (Hash << 16) - Hash + CurrChar;
                }

                return (Hash & ::Wiz::Index32::Max);
            }

            /// Case insensitive
            ::Wiz::Index32::Type CalcInCase(::Wiz::Char::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = ::Wiz::ToUpper(*InStr++))
                {
                    /// equivalent to: hash = 65599*hash + (*str++);
                    Hash = (Hash << 6) + (Hash << 16) - Hash + CurrChar;
                }

                return (Hash & ::Wiz::Index32::Max);
            }
            ::Wiz::Index32::Type CalcInCase(::Wiz::WChar::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = ::Wiz::ToUpper(*InStr++))
                {
                    /// equivalent to: hash = 65599*hash + (*str++);
                    Hash = (Hash << 6) + (Hash << 16) - Hash + CurrChar;
                }

                return (Hash & ::Wiz::Index32::Max);
            }
        } /// end of namespace SDBM


        namespace AP
        {
            /// Case sensitive
            ::Wiz::Index32::Type Calc(::Wiz::Char::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;
                register ::Wiz::Int::Type i = 0;

                for (; CurrChar = *InStr++; ++i)
                {
                    if ((i & 1) == 0)
                    {
                        Hash ^= ((Hash << 7) ^ CurrChar ^ (Hash >> 3));
                    }
                    else
                    {
                        Hash ^= (~((Hash << 11) ^ CurrChar ^ (Hash >> 5)));
                    }
                }

                return (Hash & ::Wiz::Index32::Max);
            }
            ::Wiz::Index32::Type Calc(::Wiz::WChar::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;
                register ::Wiz::Int::Type i = 0;

                for (; CurrChar = *InStr++; ++i)
                {
                    if ((i & 1) == 0)
                    {
                        Hash ^= ((Hash << 7) ^ CurrChar ^ (Hash >> 3));
                    }
                    else
                    {
                        Hash ^= (~((Hash << 11) ^ CurrChar ^ (Hash >> 5)));
                    }
                }

                return (Hash & ::Wiz::Index32::Max);
            }

            /// Case insensitive
            ::Wiz::Index32::Type CalcInCase(::Wiz::Char::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;
                register ::Wiz::Int::Type i = 0;

                for (; CurrChar = ::Wiz::ToUpper(*InStr++); ++i)
                {
                    if ((i & 1) == 0)
                    {
                        Hash ^= ((Hash << 7) ^ CurrChar ^ (Hash >> 3));
                    }
                    else
                    {
                        Hash ^= (~((Hash << 11) ^ CurrChar ^ (Hash >> 5)));
                    }
                }

                return (Hash & ::Wiz::Index32::Max);
            }
            ::Wiz::Index32::Type CalcInCase(::Wiz::WChar::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type Hash = 0;
                register ::Wiz::UInt32::Type CurrChar;
                register ::Wiz::Int::Type i = 0;

                for (; CurrChar = ::Wiz::ToUpper(*InStr++); ++i)
                {
                    if ((i & 1) == 0)
                    {
                        Hash ^= ((Hash << 7) ^ CurrChar ^ (Hash >> 3));
                    }
                    else
                    {
                        Hash ^= (~((Hash << 11) ^ CurrChar ^ (Hash >> 5)));
                    }
                }

                return (Hash & ::Wiz::Index32::Max);
            }
        } /// end of namespace AP

        namespace JS
        {
            /// Case sensitive
            ::Wiz::Index32::Type Calc(::Wiz::Char::ConstPtr InStr)
            {
                /// 0x4E67C6A7 == 1315423911
                register ::Wiz::UInt32::Type Hash = 0x4E67C6A7;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = *InStr++)
                {
                    Hash ^= ((Hash << 5) + CurrChar + (Hash >> 2));
                }

                return (Hash & 0x7FFFFFFF);
            }
            ::Wiz::Index32::Type Calc(::Wiz::WChar::ConstPtr InStr)
            {
                /// 0x4E67C6A7 == 1315423911
                register ::Wiz::UInt32::Type Hash = 0x4E67C6A7;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = *InStr++)
                {
                    Hash ^= ((Hash << 5) + CurrChar + (Hash >> 2));
                }

                return (Hash & 0x7FFFFFFF);
            }

            /// Case insensitive
            ::Wiz::Index32::Type CalcInCase(::Wiz::Char::ConstPtr InStr)
            {
                /// 0x4E67C6A7 == 1315423911
                register ::Wiz::UInt32::Type Hash = 0x4E67C6A7;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = ::Wiz::ToUpper(*InStr++))
                {
                    Hash ^= ((Hash << 5) + CurrChar + (Hash >> 2));
                }

                return (Hash & 0x7FFFFFFF);
            }
            ::Wiz::Index32::Type CalcInCase(::Wiz::WChar::ConstPtr InStr)
            {
                /// 0x4E67C6A7 == 1315423911
                register ::Wiz::UInt32::Type Hash = 0x4E67C6A7;
                register ::Wiz::UInt32::Type CurrChar;

                while (CurrChar = ::Wiz::ToUpper(*InStr++))
                {
                    Hash ^= ((Hash << 5) + CurrChar + (Hash >> 2));
                }

                return (Hash & 0x7FFFFFFF);
            }
        } /// end of namespace JS

        namespace NoName
        {
            /// Case sensitive
            ::Wiz::Index32::Type Calc(::Wiz::Char::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type i;
                register ::Wiz::UInt32::Type Hash = 0;

                for (i = 0; InStr[i] != 0; ++i)
                {
                    Hash ^= InStr[i] << (i & 0x07); /// 0111
                }

                return (Hash & 0x7FFFFFFF);
            }
            ::Wiz::Index32::Type Calc(::Wiz::WChar::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type i;
                register ::Wiz::UInt32::Type Hash = 0;

                for (i = 0; InStr[i] != 0; ++i)
                {
                    Hash ^= InStr[i] << (i & 0x07); /// 0111
                }

                return (Hash & 0x7FFFFFFF);
            }

            /// Case insensitive
            ::Wiz::Index32::Type CalcInCase(::Wiz::Char::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type i;
                register ::Wiz::UInt32::Type Hash = 0;

                for (i = 0; InStr[i] != 0; ++i)
                {
                    Hash ^= ::Wiz::ToUpper(InStr[i]) << (i & 0x07); /// 0111
                }

                return (Hash & 0x7FFFFFFF);
            }
            ::Wiz::Index32::Type CalcInCase(::Wiz::WChar::ConstPtr InStr)
            {
                register ::Wiz::UInt32::Type i;
                register ::Wiz::UInt32::Type Hash = 0;

                for (i = 0; InStr[i] != 0; ++i)
                {
                    Hash ^= ::Wiz::ToUpper(InStr[i]) << (i & 0x07); /// 0111
                }

                return (Hash & 0x7FFFFFFF);
            } 
        } /// end of namespace NoName
    } /// end of namespace StringHash
} /// end of namespace Wiz
